package com.fastloan.mgt.application.contract.service.impl;

import com.fastloan.common.BasicServiceImpl;
import com.fastloan.common.model.CheckResult;
import com.fastloan.mgt.application.base.enums.ApplicationStatusEnum;
import com.fastloan.mgt.application.base.model.Application;
import com.fastloan.mgt.application.base.model.ApplicationVo;
import com.fastloan.mgt.application.base.service.ApplicationService;
import com.fastloan.mgt.application.base.util.ApplicationUtil;
import com.fastloan.mgt.application.contract.dao.ApplicationContractFileMapper;
import com.fastloan.mgt.application.contract.dao.ApplicationLoanResultMapper;
import com.fastloan.mgt.application.contract.model.ApplicationContract;
import com.fastloan.mgt.application.contract.model.ApplicationContractFile;
import com.fastloan.mgt.application.contract.model.ApplicationLoanResult;
import com.fastloan.mgt.application.contract.service.ApplicationContractService;
import com.fastloan.mgt.application.contract.service.LoanCallback;
import com.fastloan.mgt.application.contract.service.impl.loanmode.LoanMode;
import com.fastloan.mgt.application.contract.service.impl.loanmode.mode.ry.RYLoanMode;
import com.fastloan.mgt.application.contract.service.impl.loanmode.mode.ry.enmus.RyLoanStatusEnum;
import com.fastloan.mgt.model.model.Model;
import com.fastloan.mgt.model.service.ModelCalculateService;
import com.fastloan.mgt.processcontrol.base.service.ProcessDispatcher;
import com.fastloan.mgt.processcontrol.base.util.BeanFactoryUtil;
import com.fastloan.mgt.product.basics.dao.ProductMapper;
import com.fastloan.mgt.product.basics.model.Product;
import com.fastloan.safe.core.util.ManagerKit;
import com.fastloan.safe.mgt.sys.model.CmuSysFile;
import com.fastloan.safe.mgt.sys.service.CmSysFileService;
import com.fastloan.utils.DateTimeUtil;
import com.kawins.result.ResultEnum;
import com.kawins.result.ResultTo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;

import static com.fastloan.utils.DateTimeUtil.DIGIT_DATETIME_PATTERN;
import static java.util.stream.Collectors.toList;

/**
 * @author yanwe
 * createTime 2017-11-2017/11/11 16:18
 */
@Service
public class ApplicationContractServiceImpl extends BasicServiceImpl<ApplicationContract> implements ApplicationContractService {

    @Autowired
    private ApplicationContractFileMapper applicationContractFileMapper;

    @Autowired
    private ApplicationService applicationService;

    @Autowired
    private CmSysFileService cmSysFileService;

    @Autowired
    private ModelCalculateService modelCalculateService;

    @Autowired
    private ProductMapper productMapper;

    @Override
    @Transactional
    public CheckResult contract(ApplicationContract applicationContract, MultipartFile[] files) {
        if (check(applicationContract)) return new CheckResult("该进件已签约");
        Application selectApp = applicationService.selectByPrimaryKey(applicationContract.getApplicationId());
        Product product = productMapper.selectByPrimaryKey(selectApp.getProductId());

        Map<String, LoanMode> loanModeMap = BeanFactoryUtil.getBeansOfType(LoanMode.class);
        Optional<LoanMode> loanModeOptional = loanModeMap.values().stream()
                .filter(loanMode -> loanMode.loanMode().getType().equals(product.getFundingId())).findFirst();
        if (!loanModeOptional.isPresent()){
            String errorMsg = "未知的资金方类型:" + product.getFundingId();
            log.error(errorMsg);
            return CheckResult.fail(errorMsg);
        }
        //放款
        CheckResult checkResult = loanModeOptional.get().loan(applicationContract);
        if (!checkResult.isCheckResult()){
            return checkResult;
        }
        applicationContract.setCreateBy(ManagerKit.getUserId());
        applicationContract.setContractTime(new Date());
        insertSelective(applicationContract);
        upLoad(files, ApplicationContractFile::new, applicationContract.getContractId())
                .entrySet().stream().map(Map.Entry::getValue)
                .forEach(applicationContractFileMapper::insert);
        //更新放款金额
        Application application = new Application();
        application.setApplicationId(applicationContract.getApplicationId());
        application.setLoanAmount(applicationContract.getLoanAmount());
        application.setLoanTime(applicationContract.getLoanTime());
        applicationService.updateByPrimaryKeySelective(application);
        //回调模型通知
        callBackModelResult(applicationContract,true);
        return CheckResult.success();
    }

    @Override
    public ApplicationVo getApplicationVo(String applicationId) {
        ApplicationVo applicationVo = applicationService.selectApplicationVo(applicationId);
        if (applicationVo == null){
            return null;
        }
        applicationVo.setLoanAmount(ApplicationUtil.getFinalAmount(applicationVo.getApplicationId()
                ,applicationVo.getAuditAmount(),applicationVo.getApplyAmount()));
        return applicationVo;
    }

    @Override
    public ApplicationContract getContractInfo(String applicationId) {
        ApplicationContract criteria = new ApplicationContract();
        criteria.setApplicationId(applicationId);
        ApplicationContract applicationContract = selectOne(criteria);
        if (applicationContract == null) {
            return null;
        }
        ApplicationContractFile contractFileCriteria = new ApplicationContractFile();
        contractFileCriteria.setContractId(applicationContract.getContractId());
        List<CmuSysFile> files = applicationContractFileMapper.select(contractFileCriteria).stream()
                .map(applicationContractFile -> cmSysFileService
                        .selectByPrimaryKey(applicationContractFile.getFileId()))
                .collect(toList());
        applicationContract.setFiles(files);
        return applicationContract;
    }

    @Override
    public void rejectContract(String applicationId) {
        applicationService.modifyApplicationStatus(applicationId, ApplicationStatusEnum.SIGNED_REJECT);
        ApplicationContract applicationContract = new ApplicationContract();
        applicationContract.setApplicationId(applicationId);
        callBackModelResult(applicationContract,false);
    }

    @Override
    public CheckResult agreeContract(String applicationId, boolean agree) {
        Application application = applicationService.selectByPrimaryKey(applicationId);
        boolean haveNext = ProcessDispatcher.isHaveNext(application.getProcessId());
        if (haveNext) {
            return new CheckResult("该进件流程未结束无法同意或拒绝签约！");
        }
        applicationService.modifyApplicationStatus(applicationId, agree ? ApplicationStatusEnum.WAIT_SIGNED
                : ApplicationStatusEnum.CUSTOMER_REJECT_SIGNED);
        return new CheckResult();
    }

    @Override
    public List<String> queryContractFileIds(String applicationId) {
        ApplicationContract contract = new ApplicationContract();
        contract.setApplicationId(applicationId);
        List<ApplicationContract> applicationContractList = select(contract);
        List<List<String>> listList = applicationContractList.stream()
                .map(ApplicationContract::getContractId)
                .map(contractId -> {
                    ApplicationContractFile contractFile = new ApplicationContractFile();
                    contractFile.setContractId(contractId);
                    List<ApplicationContractFile> contractFileList = applicationContractFileMapper.select(contractFile);
                    return contractFileList.stream()
                            .filter(Objects::nonNull)
                            .map(ApplicationContractFile::getFileId)
                            .collect(toList());
                }).collect(toList());
        List<String> fileIds = new ArrayList<>();
        listList.forEach(fileIds::addAll);
        return fileIds;
    }

    @Override
    public ResultTo loanCallback(ApplicationLoanResult loanResult) {
        Map<String, LoanMode> loanModeMap = BeanFactoryUtil.getBeansOfType(LoanMode.class);
        Optional<LoanMode> loanMode = loanModeMap.values().stream()
                .filter(ryLoanMode -> loanResult.getLoanModeEnum().equals(ryLoanMode.loanMode()))
                .findFirst();
        if (!loanMode.isPresent()){
            log.error("未知的放款方式,进件ID:"+loanResult.getApplicationId());
            return new ResultTo(ResultEnum.OPERATION_FAILED,"未知的放款模式");
        }
        CheckResult checkResult = loanMode.get().loanCallback(loanResult);
        if (!checkResult.isCheckResult()){
            return new ResultTo(ResultEnum.OPERATION_FAILED,checkResult.getCheckMsg());
        }
        return new ResultTo();
    }

    private boolean check(ApplicationContract applicationContract) {
        String applicationId = applicationContract.getApplicationId();
        ApplicationContract criteria = new ApplicationContract();
        criteria.setApplicationId(applicationId);
        int count = selectCount(criteria);
        return count != 0;
    }

    private void callBackModelResult(ApplicationContract applicationContract,boolean isPass) {
        Application application = applicationService.selectByPrimaryKey(applicationContract.getApplicationId());
        Product product = productMapper.selectByPrimaryKey(application.getProductId());
        Optional<Model> modelOptional = modelCalculateService.choiceModel(product.getModelType());
        modelOptional.ifPresent(model -> model.getModelHandler().sendBack(applicationContract, isPass));
    }

}
